import * as THREE from "../../../modules/three/three.module.js";
import {DRACOLoader} from "../../../modules/three/jsm/loaders/DRACOLoader.js";
import {GLTFLoader} from "../../../modules/three/jsm/loaders/GLTFLoader.js";


const dracoLoader = new DRACOLoader();
// const DRACO_DECODER_PATH = 'https://unpkg.com/three@0.123.0/examples/js/libs/draco/gltf/';
const DRACO_DECODER_PATH = '../public/3d/gltf_draco/';
dracoLoader.setDecoderPath( DRACO_DECODER_PATH );
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);

// -2 为地块模型的厚度
const mapViewHitPlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), -5);
const lightsHitPlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), -7);
export {gltfLoader, mapViewHitPlane, lightsHitPlane}

export function getCurrentDateStr() {
  const curTime = new Date();
  // const curTime = time ? new Date(time) : new Date();
  const addMinute = new Date(curTime.setMinutes(curTime.getMinutes()));
  const da = new Date(addMinute);
  const year = da.getFullYear();
  let month = da.getMonth() + 1;
  month = month > 9 ? month : '0' + month;
  const date = da.getDate();
  const H = da.getHours();
  const M = da.getMinutes();
  const s = da.getSeconds() > 9 ? da.getSeconds() : '0' + da.getSeconds();
  return [year, month, date].join('-') + ' ' + [H, M, s].join(':');
}

export function modifyEquirectVertShader() {
  THREE.ShaderLib.equirect.vertexShader = `
    varying vec3 vWorldDirection;

    #include <common>

    void main() {
      vWorldDirection = transformDirection( position, modelMatrix );
      float tmp = vWorldDirection.y;
      vWorldDirection.y = vWorldDirection.z;
      vWorldDirection.z = -tmp;

      #include <begin_vertex>
      #include <project_vertex>
    }
    `
}
/**
 * 修改环境贴图的顶点着色器，解决camera.up设置为 z 轴后，旋转相机时，环境贴图的旋转不正确的问题
 */
export function modifyCubeVertShader() {
  THREE.ShaderLib.backgroundCube.vertexShader = `
    varying vec3 vWorldDirection;

    #include <common>

    void main() {

      vWorldDirection = transformDirection( position, modelMatrix );
      float tmp = vWorldDirection.y;
      vWorldDirection.y = vWorldDirection.z;
      vWorldDirection.z = -tmp;

      #include <begin_vertex>
      #include <project_vertex>

      gl_Position.z = gl_Position.w; // set z to camera.far

    }
    `
}
/**
 * 还原对THREE环境贴图的顶点着色器的修改，解决实时渲染页面的相机旋转不正确的问题
 */
export function unmodifyCubeVertShader() {
  THREE.ShaderLib.cube.vertexShader = `
    varying vec3 vWorldDirection;

    #include <common>

    void main() {

      vWorldDirection = transformDirection( position, modelMatrix );

      #include <begin_vertex>
      #include <project_vertex>

      gl_Position.z = gl_Position.w; // set z to camera.far

    }
    `
}

// eslint-disable-next-line require-jsdoc
export function getLocalItem(key) {
  const data = localStorage.getItem(key)
  if (!data) {
    return null
  }
  try {
    return JSON.parse(data)
  } catch (e) {
    console.error(e)
    return null
  }
}

export function setLocalItem(key, value) {
  if (value === undefined || value === null) {
    localStorage.removeItem(key)
  } else {
    localStorage.setItem(key, JSON.stringify(value))
  }
}

export function getModelNameFromUrl(url) {
  const index1 = url.lastIndexOf('/');
  const index2= url.lastIndexOf('.');
  const name = url.substring(index1 + 1, index2);
  return name;
}

export function clamp(val, min, max) {
  if (val > max) {
    return max;
  }
  if (val < min) {
    return min;
  }
  return val;
}

export const LightModeEnum = {
  onlyNight: 'onlyNight', // 仅黑夜
  onlyDay: 'onlyDay', // 仅白天
  wholeDay: 'wholeDay', // 全天
}

/**
 *
 * @param {LightVO} vo
 * @see LightModeEnum
 * @param {number} angle
 */
export function updateLightIntensity(vo, angle) {
  let start, end;
  const a2 = 0.15;
  const mode = vo.workTime;
  if (mode === LightModeEnum.onlyNight || mode === LightModeEnum.wholeDay) {
    if (angle >= 150 && angle <= 180) {
      // 下午4点 到 下午6点
      const a1 = mode === LightModeEnum.onlyNight ? 0.01 : 0.9;
      start = a1 * vo.intensity;
      end = a2 * vo.intensity;
      const t = (angle - 150) / 30;
      return THREE.MathUtils.lerp(start, end, t);
    } else if (angle > 180) {
      // 下午6点 到 下午8点
      start = a2 * vo.intensity;
      const v = THREE.MathUtils.smootherstep(angle, 180, 210);
      return start + v * (1 - a2) * vo.intensity;
    } else {
      if (mode === LightModeEnum.onlyNight) {
        return 0;
      } else {
        return vo.intensity;
      }
    }
  } else { // 只在清晨和白昼显示的灯光
    return angle < 150 ? vo.intensity : 0;
  }
}

export function getSunIntensityRatio(angle) {
  if (angle <= 90) {
    const t = angle / 90;
    return 0.1 + 0.9 * t;
  } else if (angle <= 180) {
    const v = THREE.MathUtils.smootherstep(angle, 95, 175);
    return 0.5 + 0.5 * (1 - v);
  } else {
    const v = 1 - THREE.MathUtils.smootherstep(angle, 180, 215);
    return 0.15 + 0.35 * v;
  }
}

export function updateBloomStrength(maxStrength, angle) {
  let start, end;
  const a1 = 0.1;
  const a2 = 0.3;
  if (angle >= 150 && angle <= 180) {
    // 下午4点 到 下午6点
    start = a1 * maxStrength;
    end = a2 * maxStrength;
    const t = (angle - 150) / 30;
    return THREE.MathUtils.lerp(start, end, t);
  } else if (angle > 180) {
    start = a2 * maxStrength;
    const v = THREE.MathUtils.smootherstep(angle, 180, 210);
    return start + v * (1 - a2) * maxStrength;
  } else if (angle <= 30) {
    start = maxStrength;
    end = 0.3 * maxStrength;
    const t = angle / 30;
    return THREE.MathUtils.lerp(start, end, t);
  }
  return 0;
}

/**
 * jscolor库拷贝; 参数r，g，b都是 0到255之间的整数
 * @param {number} r
 * @param {number} g
 * @param {number} b
 */
function isLightColor(r, g, b) {
  return (
    0.213 * r +
    0.715 * g +
    0.072 * b >
    255 / 2
  );
}

/**
 * @param {string} cssColorStr, css 颜色字符串，如 ‘#fdfddf'
 * @return {boolean}
 */
export function isLightCssColor(cssColorStr) {
  const r = Number('0x' + cssColorStr.slice(1,3));
  const g = Number('0x' + cssColorStr.slice(3,5));
  const b = Number('0x' + cssColorStr.slice(5,7));
  return isLightColor(r, g, b);
}

/**
 * 求两个字符串的最长公共子序列
 * @param {string} str1
 * @param {string} str2
 * @return {number} 最长公共子序列的长度
 */
export function LCS(str1, str2) {
  const m = str1.length;
  const n = str2.length;
  const dp = [new Array(n + 1).fill(0)]; //第一行全是0
  for (let i = 1; i <= m; i++) {
    //一共有m+1行
    dp[i] = [0]; //第一列全是0
    for (let j = 1; j <= n; j++) {
      //一共有n+1列
      if (str1[i - 1] === str2[j - 1]) {
        //注意这里，str1的第一个字符是在第二列中，因此要减1，str2同理
        dp[i][j] = dp[i - 1][j - 1] + 1; //对角＋1
      } else {
        dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
      }
    }
  }
  return dp[m][n];
}

/**
 * 防抖函数
 * @param {() => {}} fn
 * @param {number} wait
 * @return {() => {}}
 */
export function debounce(fn, wait) {
  let timer = null;
  return function () {
    if (timer !== null) {
      clearTimeout(timer);
    }
    timer = setTimeout(fn, wait);
  };
}

export function isEntitySelectable(entity) {
  return entity.visible && !entity.locked;
}

export function randBetween(min, max) {
  const span = max - min
  return min + span * Math.random()
}
